package cn.lysj.framework.api.controller;

import cn.lysj.framework.api.base.ApiContent;
import cn.lysj.framework.api.enumerate.PayWay;
import cn.lysj.framework.common.OrderPayConstant;
import cn.lysj.framework.common.domain.User;
import cn.lysj.framework.common.exception.MyException;
import cn.lysj.framework.common.utils.http.HttpUtil;
import cn.lysj.framework.common.utils.json.JacksonUtil;
import cn.lysj.framework.common.utils.string.StringCuttingUtil;
import cn.lysj.framework.common.utils.web.ParamUtil;
import cn.lysj.framework.common.utils.web.Resp;
import cn.lysj.framework.common.utils.websocket.IncidentType;
import cn.lysj.framework.common.utils.websocket.WebSocketServerToStore;
import cn.lysj.framework.common.utils.websocket.WebSocketServerToUser;
import cn.lysj.framework.customer.domain.CustomerVip;
import cn.lysj.framework.customer.domain.CustomerVipCoupon;
import cn.lysj.framework.customer.service.CustomerVipService;
import cn.lysj.framework.customer.vo.CustomerVipCouponVo;
import cn.lysj.framework.customer.vo.CustomerVipInfoVo;
import cn.lysj.framework.order.util.wx.UnifiedOrderUtil;
import cn.lysj.framework.order.util.wx.WXPayUtil;
import cn.lysj.framework.order.util.wx.WxPublicUtil;
import cn.lysj.framework.customer.domain.Customer;
import cn.lysj.framework.foodv2.domain.Food;
import cn.lysj.framework.order.domain.FoodOrder;
import cn.lysj.framework.order.domain.FoodOrderInfo;
import cn.lysj.framework.order.dto.*;
import cn.lysj.framework.order.vo.FoodOrderVo;
import cn.lysj.framework.store.domain.Store;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * @ Author ：drj.
 * @ Date  ：Created in 9:14 2018/11/13
 * @ Description:
 **/
@Slf4j
@RestController
@RequestMapping("/app/v2/user")
public class AppOrderController extends ApiContent {


    @PostMapping("/create_order")
    public Resp createOrder(String orderId,  //订单Id
                            Integer repastWay,  //用餐方式 1.现吃 2.外带
                            String foodOrderRemark, //订单备注
                            Integer useFoodNumber, //用餐人数
                            Integer supporyPayWay, //1.线上 2.线下
                            String customerVipCouponId,//用户使用优惠券
                            Integer type           //支付类型 1.支付页面 2.我的订单页面
    ) {
        FoodOrder foodOrder = foodOrderService.getRepository().findOne(orderId);
        if (foodOrder == null) {
            return new Resp(Resp.PARAM_ERROR, "订单信息有误");
        }


        //如果在支付页面支付需要输入 用餐方式 订单备注 如果现吃需要加入 就餐人数
        if (type == 2) {
            repastWay = foodOrder.getRepastWay();
            useFoodNumber = foodOrder.getUseFoodNumber();
            supporyPayWay = foodOrder.getSupporyPayWay();
        }
        //获取支付金额
        BigDecimal useMoney = useMoney(repastWay, foodOrder, useFoodNumber);
        if (type == 1) {
            //获取该商户的第三方merchantId
            if (ParamUtil.isBlank(repastWay)) {
                return new Resp(Resp.PARAM_ERROR, "支付失败,请确认就餐方式!");
            }
            //订单状态如果不是 -2.预留订单 -1.未支付 则说明订单已经生成，提示用户不准重复下单
            if (foodOrder.getFoodOrderStatus() != -1 && foodOrder.getFoodOrderStatus() != -2) {
                return new Resp(Resp.PARAM_ERROR, "订单已经生成,请勿重复操作!");
            }
            //如果用户使用了优惠券
            if (!ParamUtil.isBlank(customerVipCouponId)) {
                CustomerVipCouponVo customerVipCouponVo = customerVipCouponService.getRepository().findAssignCustomerVipCouponVo(customerVipCouponId, 1, new Date(), useMoney);
                if (customerVipCouponVo == null) {
                    return new Resp(Resp.PARAM_ERROR, "该优惠券已失效,请重新选择使用优惠券");
                }
                CustomerVipCoupon customerVipCoupon = customerVipCouponService.getRepository().findOne(customerVipCouponVo.getCustomerVipCouponId());
                customerVipCoupon.setUseType(2);
                customerVipCouponService.save(customerVipCoupon);
                foodOrder.setDiscountMoney(customerVipCouponVo.getDiscountMoney());
            }
            foodOrder.setRepastWay(repastWay);
            foodOrder.setFoodOrderRemark(foodOrderRemark);
            foodOrder.setSupporyPayWay(supporyPayWay);
            foodOrder.setCustomerVipCouponId(customerVipCouponId);
            if (repastWay == 1) {
                foodOrder.setUseFoodNumber(useFoodNumber);//就餐人数
            }
        }
        //将该订单设置为未支付状态
        foodOrder.setFoodOrderStatus(-1);
        BigDecimal payMoney = sumOrderMoney(repastWay, foodOrder, useFoodNumber);
        foodOrder.setActPayMoney(payMoney);
        foodOrderService.getRepository().save(foodOrder);
        //支付部分
        if (supporyPayWay == PayWay.ONLINE) {
            if (payMoney.compareTo(BigDecimal.ZERO) == 0) {
                sendWebSocketServer(foodOrder);
                foodOrder.setFoodOrderStatus(1);
                foodOrderService.getRepository().save(foodOrder);
                Map<String, Object> resultMap = new HashMap<>();
                resultMap.put("payStatus", 1);
                return new Resp(resultMap, "下单成功,请耐心等待!");
            }
            return orderPay(foodOrder, payMoney);
        } else if (supporyPayWay == PayWay.OFFLINE) {
            //webSocket请求
            sendWebSocketServer(foodOrder);
            //修改状态
            foodOrder.setFoodOrderStatus(6);
            //修改下单时间
            foodOrder.setCreateTime(new Date());
            //保存
            foodOrderService.getRepository().save(foodOrder);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("payStatus", 1);
            return new Resp(resultMap, "下单成功,请耐心等待!");
        } else {
            return new Resp(Resp.PARAM_ERROR, "支付形式异常!");
        }
    }


    //发起支付
    private Resp orderPay(FoodOrder foodOrder, BigDecimal payMoney) {
        User user = userService.getRepository().findByStoreId(foodOrder.getStoreId());
        String subject = StringCuttingUtil.substring(foodOrder.getSubject(), 0, 15);
        subject = subject.replaceAll(",", "");
        if (foodOrder.getSubject().length() > 15) {
            subject += "";
        }
        if (1 == foodOrder.getPayWay()) {
            AliOrderDto aliOrderDto = new AliOrderDto();
            aliOrderDto.setMerchantId(user.getMerchantId());
            aliOrderDto.setEatTableId(foodOrder.getEatTableId());
            aliOrderDto.setStoreId(foodOrder.getStoreId());
            aliOrderDto.setSubject(subject);
            aliOrderDto.setTotalAmount(payMoney);
            aliOrderDto.setBody("支付宝支付");
            System.out.println("阿里支付商户号:" + aliOrderDto.getMerchantId());
            System.out.println("阿里支付订单金额:" + aliOrderDto.getTotalAmount());
            System.out.println("阿里支付订单描述:" + aliOrderDto.getBody());
            System.out.println("阿里支付主题:" + aliOrderDto.getSubject());
            RestTemplate restTemplate = new RestTemplate();
            AjaxResp resp = restTemplate.postForObject(OrderPayConstant.ALICREATEORDER, aliOrderDto, AjaxResp.class);
            //若成功支付,记录返回的单号,回调使用
            if (resp.getStatus().equals(AjaxResp.Status.SUCCESS)) {
                foodOrder.setOtherOrderNumber(resp.getMsg());
                foodOrderService.getRepository().save(foodOrder);
                return new Resp(resp.getObj());
            } else {
                return new Resp(Resp.PARAM_ERROR, "支付异常,请重试!");
            }
        } else if (2 == foodOrder.getPayWay()) {

            //获取用户的openId
            Customer customer = customerService.findOne(foodOrder.getCustomerId());
            //组装微信支付所需参数
            PayParam payParam = new PayParam();
            payParam.setAttach(user.getAttach());
            payParam.setMchId(user.getMchId());
            payParam.setOrgNo(user.getOrgNo());
            payParam.setDeviceInfo(user.getDeviceInfo());
            payParam.setAppKey(user.getAppKey());
            payParam.setOpenid(customer.getFlagId());
            payParam.setNonceStr(ParamUtil.uuid());
            payParam.setOutTradeNo(foodOrder.getFoodOrderNumber());

            //获取支付费用
            payParam.setTotalFee(Integer.valueOf(payMoney.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString()));
            String result = WxPublicUtil.getPrepayId(payParam); // 向微信服务器获取统一下单订单号
            log.info("请求返回的数据:" + result);
            //解析返回的xml信息
            Map<String, String> map = new HashMap<String, String>();
            try {
                map = WxPublicUtil.xmlToMap(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if ("SUCCESS".equals(map.get("return_code"))) {
                log.info("返回给前端唤醒支付参数:" + JacksonUtil.toJson(map));
                return new Resp(map);
            } else {
                log.info("发起统一下单接口时返回的数据:\n" + result);
                return new Resp(Resp.PARAM_ERROR, "发起参数支付异常");
            }
        } else {
            return new Resp(Resp.PARAM_ERROR, "支付方式异常");
        }
    }


    /**
     * @author drj
     * @date 2018/12/26 15:22
     * @Description
     */
    @PostMapping("/ali_order_callback")
    public boolean aliOrderCallback(@RequestBody String out_trade_no) {
        return callBack(out_trade_no);
    }

    @PostMapping("/wx_order_callback")
    public void wxOrderCallback() throws Exception {
        log.info("进入支付回调");
        BufferedReader br = request.getReader();

        String str = "";
        StringBuilder sb = new StringBuilder();
        while ((str = br.readLine()) != null) {
            sb.append(str);
        }
        Map<String, String> resultMap = WxPublicUtil.xmlToMap(sb.toString());
        //支付订单号
        String out_trade_no = new String(resultMap.get("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
        //回调订单号
        String trade_no = new String(resultMap.get("transaction_id").getBytes("ISO-8859-1"), "UTF-8");
        // 交易状态
        String return_code = new String(resultMap.get("return_code").getBytes("ISO-8859-1"), "UTF-8");
        //交易金额
        String total_fee = new String(resultMap.get("total_fee").getBytes("ISO-8859-1"), "UTF-8");

        FoodOrder foodOrder = foodOrderService.getRepository().findByFoodOrderNumber(out_trade_no);
        if (null == foodOrder || foodOrder.getFoodOrderStatus() != -1) {
            String returnxml = "<xml>" +
                    "   <return_code><![CDATA[FAIL]]></return_code>" +
                    "   <return_msg><![CDATA[返回消息失败]]></return_msg>" +
                    "</xml>";
            response.getWriter().write(returnxml);
            response.getWriter().flush();
        }
        //获取订单对应的商户
        User user = userService.getRepository().findByStoreId(foodOrder.getStoreId());

        BigDecimal payMoney = foodOrder.getActPayMoney();
        //校验签名
        boolean signResutl = WXPayUtil.isSignatureValid(resultMap, user.getAppKey());
        if (signResutl && (new BigDecimal(total_fee).compareTo(payMoney.multiply(new BigDecimal("100")).stripTrailingZeros()) == 0) && out_trade_no.equals(foodOrder.getFoodOrderNumber())) {        // 签名正确
            if ("SUCCESS".equals(return_code)) {
                foodOrder.setFoodOrderStatus(1);
                foodOrder.setTradeOrderNumber(trade_no); //保存支付回调单号,退款使用
                foodOrder.setCreateTime(new Date());
                foodOrder.setUpdateTime(new Date());
                sendWebSocketServer(foodOrder);
                log.info("进入打印" + foodOrder.getPayWay());
                foodOrderService.getRepository().save(foodOrder);
                String returnxml = "<xml>" +
                        "   <return_code><![CDATA[SUCCESS]]></return_code>" +
                        "   <return_msg><![CDATA[OK]]></return_msg>" +
                        "</xml>";
                response.getWriter().write(returnxml);
                response.getWriter().flush();
            } else {
                String returnxml = "<xml>" +
                        "   <return_code><![CDATA[FAIL]]></return_code>" +
                        "   <return_msg><![CDATA[返回消息失败]]></return_msg>" +
                        "</xml>";
                response.getWriter().write(returnxml);
                response.getWriter().flush();
            }
        } else {
            log.error("回调发生错误，支付订单号为{}，回调订单号为{},交易金额为{}", out_trade_no, trade_no, total_fee);
            String returnxml = "<xml>" +
                    "   <return_code><![CDATA[FAIL]]></return_code>" +
                    "   <return_msg><![CDATA[返回消息失败]]></return_msg>" +
                    "</xml>";
            response.getWriter().write(returnxml);
            response.getWriter().flush();
        }
    }

    private boolean callBack(String out_trade_no) {
        System.out.println("进入调界面");
        FoodOrder foodOrder = foodOrderService.getRepository().findByOtherOrderNumber(out_trade_no);
        if (foodOrder == null || foodOrder.getFoodOrderStatus() != -1) {
            return true;
        }
        foodOrder.setFoodOrderStatus(1); //支付完成
        foodOrder.setCreateTime(new Date());
        foodOrder.setUpdateTime(new Date());
        foodOrderService.getRepository().save(foodOrder);
        //调用通知websocket接口 通知新订单提示,顺带发送订单详情
        sendWebSocketServer(foodOrder);
        log.info("进入打印" + foodOrder.getPayWay());
        return true;
    }

    //给对应人员发送已经完成订单确认
    private void sendWebSocketServer(FoodOrder foodOrder) {
        //通知有新订单
        List<FoodOrderVo> foodOrderVos = new ArrayList<>();
        foodOrderService.addFoodOrderVos(foodOrderVos, foodOrder);
        Store store = storeRepository.findOne(foodOrder.getStoreId());
        Map<String, Object> foodOrderReceipt = new HashMap<>();
        foodOrderReceipt.put("foodOrderVos", foodOrderVos);
        foodOrderReceipt.put("store", store);
        WebSocketServerToStore.sendDataToMorePeopleMap(IncidentType.SEND_FOOD_ORDER_RADIO, foodOrderReceipt, foodOrder.getStoreId(), true);
    }


    /**
     * @author drj
     * @date 2018/11/13 10:42
     * @Description：申请退款
     */
    @PostMapping("/apply_for_refund")
    public Resp applyForRefund(String foodOrderId) {
        if (ParamUtil.isBlank(foodOrderId)) {
            return new Resp(Resp.PARAM_ERROR, "订单项id为空");
        }
        FoodOrder foodOrder = foodOrderService.getRepository().findOne(foodOrderId);
        if (foodOrder == null) {
            return new Resp(Resp.PARAM_ERROR, "订单项错误");
        }
        if (foodOrder.getFoodOrderStatus() != 1) {
            return new Resp(Resp.PARAM_ERROR, "该订单不允许退款，请与商家线下解决或联系平台管理员");
        }
        foodOrder.setFoodOrderStatus(3);
        foodOrderService.getRepository().save(foodOrder);
        return new Resp("操作成功");
    }


    /**
     * @author drj
     * @date 2018/11/15 10:30
     * @Description:处理退款申请
     */
    @PostMapping("/refund_handle")
    public Resp refundHandle(String foodOrderId, Integer foodOrderStatus, BigDecimal money) {
        return foodOrderService.refundHandle(foodOrderId, foodOrderStatus, money);
    }


    @GetMapping("/wxpay_redirect")
    public void wxpayRedirect() {
        try {
            response.sendRedirect("http://diet.lingyundata.com:8008/ordering/#/payment");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private void changeFoodStatus(FoodOrder foodOrder) {
        if (foodOrder.getFoodOrderStatus() == 2) {
            List<FoodOrderInfo> foodOrderInfos = foodOrderInfoService.getRepository().findByFoodOrderId(foodOrder.getId());
            List<Food> foods = new LinkedList<>();
            for (FoodOrderInfo foodOrderInfo : foodOrderInfos) {
                Food food = foodService.findOne(foodOrderInfo.getFoodId());
                food.setActSellNum(food.getActSellNum() - 1);
                food.setVirtualSellNum(food.getVirtualSellNum() - 1);
                foods.add(food);
            }
            //如果就餐方式为现吃
            if (foodOrder.getRepastWay() == 1) {
                foodOrder.setRefundMoney(foodOrder.getSumMoney());
            } else {
                foodOrder.setRefundMoney(foodOrder.getSumMoney().add(foodOrder.getAllBoMoney()));
            }
            foodService.getRepository().save(foods);
        }
    }

    //优惠后价格
    public BigDecimal sumOrderMoney(Integer repastWay, FoodOrder foodOrder, Integer useFoodNumber) {
        BigDecimal useMoney = useMoney(repastWay, foodOrder, useFoodNumber);
        useMoney = useMoney.subtract(foodOrder.getDiscountMoney());
        if (useMoney.compareTo(BigDecimal.ZERO) <= 0) {
            useMoney = BigDecimal.ZERO;
        }
        return useMoney;
    }

    //获取优惠前价格
    public BigDecimal useMoney(Integer repastWay, FoodOrder foodOrder, Integer useFoodNumber) {
        if (repastWay == 2) {
            return foodOrder.getSumMoney().add(foodOrder.getAllBoMoney());
        } else if (repastWay == 1) {
            return foodOrder.getSumMoney().add(foodOrder.getAllCutleryMoney().multiply(new BigDecimal(useFoodNumber)));
        } else {
            throw new MyException("就餐方式异常");
        }
    }


}
